package com.ssy.lingxi.contract.serviceimpl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.json.JSONUtil;
import com.ssy.lingxi.common.constant.order.OrderPayChannelEnum;
import com.ssy.lingxi.common.constant.order.OrderPayTypeEnum;
import com.ssy.lingxi.common.constant.settle.SettlementOrderTypeEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.PageData;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.common.utils.CollectionPageUtil;
import com.ssy.lingxi.contract.api.model.vo.request.ContractOrderListRequest;
import com.ssy.lingxi.contract.api.model.vo.request.PayApplyAmountVO;
import com.ssy.lingxi.contract.constant.Constants;
import com.ssy.lingxi.contract.entity.*;
import com.ssy.lingxi.contract.model.constant.*;
import com.ssy.lingxi.contract.model.vo.applyamount.request.ApplyAmountOrderDetailVO;
import com.ssy.lingxi.contract.model.vo.applyamount.request.*;
import com.ssy.lingxi.contract.model.vo.applyamount.response.*;
import com.ssy.lingxi.contract.model.vo.common.request.ContractOrderPageVO;
import com.ssy.lingxi.contract.model.vo.common.response.ContractOrderPageResponse;
import com.ssy.lingxi.contract.model.vo.common.response.PageItemVO;
import com.ssy.lingxi.contract.model.vo.common.response.TaskStepVO;
import com.ssy.lingxi.contract.repository.*;
import com.ssy.lingxi.contract.service.*;
import com.ssy.lingxi.contract.utils.CodeUtils;
import com.ssy.lingxi.contract.utils.ParamVerifyUtils;
import com.ssy.lingxi.dto.request.ApplyAmountSunQueryVO;
import com.ssy.lingxi.dto.request.InvoiceProveGetVO;
import com.ssy.lingxi.dto.response.ApplyAmountSunVO;
import com.ssy.lingxi.dto.response.InvoiceProveVO;
import com.ssy.lingxi.message.api.constant.MessageTemplateCode;
import com.ssy.lingxi.message.api.vo.request.SystemMessageRequest;
import com.ssy.lingxi.report.api.enums.ContractApplyAmountOrderOperateTypeEnum;
import com.ssy.lingxi.report.api.enums.OperateDataSourceEnum;
import com.ssy.lingxi.report.api.vo.request.OperateNoticeVO;
import com.ssy.lingxi.workflow.api.model.contant.ProcessEnum;
import com.ssy.lingxi.workflow.api.model.contant.ProcessTaskStatusEnum;
import com.ssy.lingxi.workflow.api.model.vo.request.TaskStartVO;
import com.ssy.lingxi.workflow.api.model.vo.response.SimpleTaskCompleteVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 请款单接口实现
 * @author 伍将
 * @date 2021/3/10
 * @version 2.0.0
 */
@Slf4j
@Service
public class ApplyAmountOrderServiceImpl implements IApplyAmountOrderService {

    @Resource
    private ApplyAmountOrderRepository repository;

    @Resource
    private IFeignService feignService;

    @Resource
    private IApplyAmountOrderRecordService recordService;

    @Resource
    private IApplyAmountOrderDetailService detailService;

    @Resource
    private ContractRepository contractRepository;

    @Resource
    private ContractExecuteInfoRepository contractExecuteInfoRepository;

    @Resource
    private ContractPayPlanRepository payPlanRepository;

    @Resource
    private ContractExecuteInfoRepository executeRepository;

    @Resource
    private ApplyAmountOrderDetailRepository detailRepository;

    @Resource
    IProcessFeignService processFeignService;


    /**
     * 分页查询请款单列表
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ApplyAmountOrderQueryVO>> pageList(UserLoginCacheDTO user, ApplyAmountOrderPageVO pageVO) {
        return commonPageList(user, pageVO, null);
    }

    /**
     * 查询请款单详情
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param applyId: 请款单id
     * @return 操作结果
     **/
    @Override
    public Wrapper<ApplyAmountOrderVO> getDetail(UserLoginCacheDTO user, Long applyId) {

        ApplyAmountOrderDO entity = repository.findById(applyId).orElse(null);
        if (null == entity) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_EXIST);
        }

        ApplyAmountOrderVO result = new ApplyAmountOrderVO();

        // 获取基本信息
        ApplyAmountOrderBasicsVO basics = new ApplyAmountOrderBasicsVO();
        basics.setId(entity.getId());
        basics.setApplyNo(entity.getApplyNo());
        basics.setApplyAbstract(entity.getApplyAbstract());
        basics.setStatus(entity.getStatus());
        basics.setStatusName(ApplyAmountOrderStatusEnum.getMessage(entity.getStatus()));
        basics.setContractId(entity.getContractId());
        basics.setContractNo(entity.getContractNo());
        basics.setPayeeMemberName(entity.getPayeeMemberName());
        basics.setPayeeName(entity.getPayeeName());
        basics.setBankAccount(entity.getBankAccount());
        basics.setBankDeposit(entity.getBankDeposit());
        basics.setPayPlanId(entity.getPayPlanId());
        basics.setPayStage(entity.getPayStage());
        basics.setPayRatio(entity.getPayRatio());
        basics.setApplyAmount(entity.getApplyAmount());
        basics.setExpectPayTime(DateUtil.format(DateUtil.date(entity.getExpectPayTime()), "yyyy-MM-dd"));
        basics.setPayWay(entity.getPayWay());
        basics.setPayWayName(ContractPayWayEnum.getMessage(entity.getPayWay(), entity.getPayParam()));
        basics.setPayParam(entity.getPayParam());
        basics.setMoneyPayWay(entity.getMoneyPayWay());
        basics.setMoneyPayChannel(entity.getMoneyPayChannel());
        basics.setRemark(entity.getRemark());
        basics.setOrderTime(DateUtil.format(DateUtil.date(entity.getOrderTime()), "yyyy-MM-dd HH:mm:ss"));
        basics.setSourceType(entity.getSourceType());
        result.setBasics(basics);
        //feign开票日期/编号
        InvoiceProveGetVO invoiceProveGetVO=new InvoiceProveGetVO();
        invoiceProveGetVO.setOrderNo(entity.getApplyNo());
        invoiceProveGetVO.setSettlementOrderType(SettlementOrderTypeEnum.APPLY_AMOUNT.getCode());
        List<InvoiceProveVO> invoiceProve = feignService.getInvoiceProve(invoiceProveGetVO);
        if(CollectionUtil.isNotEmpty(invoiceProve)){
            basics.setInvoiceProveVOList(invoiceProve);
        }
        // 获取内部流转步骤
        List<TaskStepVO> taskList = processFeignService.listTaskStep(entity.getTaskType(),entity.getTaskId(),entity.getMemberId());
        result.setTaskStepList(taskList);

        return Wrapper.success(result);
    }

    /**
     * 作废请款单
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param invalidVO: 作废请求参数
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Void> invalid(UserLoginCacheDTO user, ApplyAmountOrderInvalidVO invalidVO) {
        ApplyAmountOrderDO entity = repository.findById(invalidVO.getApplyId()).orElse(null);
        if (null == entity) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_EXIST);
        }
        if (ApplyAmountOrderStatusEnum.TO_BE_SUBMIT_EXAMINE.getCode().equals(entity.getStatus())
                || !ApplyAmountOrderStatusEnum.TO_BE_PAY.getCode().equals(entity.getStatus())
                || !ApplyAmountOrderStatusEnum.PAY.getCode().equals(entity.getStatus())
                || !ApplyAmountOrderStatusEnum.INVALID.getCode().equals(entity.getStatus())) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_ALLOW_INVALID);
        }

        // 更新请款单作废信息
        entity.setStatus(ApplyAmountOrderStatusEnum.INVALID.getCode());
        entity.setInvalidTime(System.currentTimeMillis());
        entity.setInvalidReason(invalidVO.getReason());
        repository.saveAndFlush(entity);

        // 新增流转记录
        recordService.add(user, entity.getId(), entity.getStatus(), null, ApplyAmountOrderActionEnum.INVALID.getMessage(), invalidVO.getReason());

        return Wrapper.success();
    }

    /**
     * 公共分页查询合同列表方法
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @param statusList: 状态列表
     * @return 操作结果
     **/
    private Wrapper<PageData<ApplyAmountOrderQueryVO>> commonPageList(UserLoginCacheDTO user, ApplyAmountOrderPageVO pageVO, List<Integer> statusList) {

        // 组装查询条件
        Specification<ApplyAmountOrderDO> spec =  (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("memberId").as(Long.class), user.getMemberId()));
            list.add(criteriaBuilder.equal(root.get("roleId").as(Long.class), user.getMemberRoleId()));
            // 组装状态条件
            if (null != statusList && statusList.size() > 0) {
                list.add(criteriaBuilder.in(root.get("status")).value(statusList));
            } else {
                if (null != pageVO.getStatus() && !ApplyAmountOrderStatusEnum.ALL.getCode().equals(pageVO.getStatus())) {
                    list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), pageVO.getStatus()));
                }
            }
            if (StringUtils.hasLength(pageVO.getStartTime())) {
                list.add(criteriaBuilder.greaterThan(root.get("orderTime").as(Long.class), DateUtil.parse(pageVO.getStartTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getEndTime())) {
                list.add(criteriaBuilder.lessThan(root.get("orderTime").as(Long.class), DateUtil.parse(pageVO.getEndTime()).getTime()));
            }
            if (StringUtils.hasLength(pageVO.getApplyNo())) {
                list.add(criteriaBuilder.like(root.get("applyNo").as(String.class), "%" + pageVO.getApplyNo().trim() + "%"));
            }
            if (StringUtils.hasLength(pageVO.getApplyAbstract())) {
                list.add(criteriaBuilder.like(root.get("applyAbstract").as(String.class), "%" + pageVO.getApplyAbstract().trim() + "%"));
            }
            if (StringUtils.hasLength(pageVO.getPayeeMemberName())) {
                list.add(criteriaBuilder.like(root.get("payeeMemberName").as(String.class), "%" + pageVO.getPayeeMemberName().trim() + "%"));
            }
            if (StringUtils.hasLength(pageVO.getContractNo())) {
                list.add(criteriaBuilder.like(root.get("contractNo").as(String.class), "%" + pageVO.getContractNo().trim() + "%"));
            }

            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        // 组装分页参数
        Pageable page = PageRequest.of(pageVO.getCurrent() - 1, pageVO.getPageSize(), Sort.by("orderTime").descending());

        Page<ApplyAmountOrderDO> result = repository.findAll(spec, page);
        List<ApplyAmountOrderQueryVO> resultList = result.getContent().stream().map(o -> {
            ApplyAmountOrderQueryVO entity = new ApplyAmountOrderQueryVO();
            entity.setId(o.getId());
            entity.setApplyNo(o.getApplyNo());
            entity.setApplyAbstract(o.getApplyAbstract());
            entity.setOrderTime(DateUtil.format(DateUtil.date(o.getOrderTime()), "yyyy-MM-dd"));
            entity.setPayeeMemberName(o.getPayeeMemberName());
            entity.setContractId(o.getContractId());
            entity.setContractNo(o.getContractNo());
            entity.setContractAmount(o.getContractAmount());
            entity.setApplyAmount(o.getApplyAmount());
            entity.setStatus(o.getStatus());
            entity.setStatusName(ApplyAmountOrderStatusEnum.getMessage(o.getStatus()));
            return entity;
        }).collect(Collectors.toList());

        return Wrapper.success(new PageData<>(result.getTotalElements(), resultList));
    }

    /**
     * 分页查询待新增请款单列表
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ApplyAmountOrderQueryVO>> pageToBeAdd(UserLoginCacheDTO user, ApplyAmountOrderCommonPageVO pageVO) {
        ApplyAmountOrderPageVO commonPageVO = new ApplyAmountOrderPageVO();
        BeanUtils.copyProperties(pageVO, commonPageVO);
        List<Integer> statusList = new ArrayList<>();
        statusList.add(ApplyAmountOrderStatusEnum.TO_BE_SUBMIT_EXAMINE.getCode());
        statusList.add(ApplyAmountOrderStatusEnum.EXAMINE_NO_PASS_1.getCode());
        statusList.add(ApplyAmountOrderStatusEnum.EXAMINE_NO_PASS_2.getCode());
        return commonPageList(user, commonPageVO, statusList);
    }

    /**
     * 根据提交的请款项，匹配数据库中的订单，构建执行计划列表
     * @param user 登录用户
     * @param saveVO 接口参数
     * @return 查询结果
     */
    private List<ContractExecuteInfoDO>  getContractOrderList(UserLoginCacheDTO user, ApplyAmountOrderSaveVO saveVO){
        ContractOrderPageVO vo=new ContractOrderPageVO();
        vo.setContractId(saveVO.getBasics().getContractId());
        vo.setCurrent(1);
        vo.setPageSize(999);
        //查询合同下的所有订单列表
        Wrapper<PageData<ContractOrderPageResponse>> pageDataWrapper = contractOrderPageList(user, vo);
        PageData<ContractOrderPageResponse> pageDate = pageDataWrapper.getData();
        if(CollectionUtil.isEmpty(pageDate.getData())){
            throw new BusinessException(ResponseCode.CONTRACT_ORDER_NOT_EXISTS);
        }
        long now = System.currentTimeMillis();
        List<ContractExecuteInfoDO> executeInfoDOS=new ArrayList<>();
        int requestNum=saveVO.getDetailList().size();
        saveVO.getDetailList().forEach(o -> pageDate.getData().forEach(od ->{
            if(o.getOrderNO().equals(od.getApplyNo())&&od.getIsHasTax().equals(o.getIsHasTax())&&od.getTaxRate().equals(o.getTaxRate())){
                ContractExecuteInfoDO executeInfoDO=new ContractExecuteInfoDO();
                executeInfoDO.setContractId(saveVO.getBasics().getContractId());
                executeInfoDO.setOrderType(od.getOrderType());
                executeInfoDO.setOrderAmount(od.getOrderAmount());
                executeInfoDO.setOrderId(od.getOrderId());
                executeInfoDO.setOrderNO(od.getApplyNo());
                executeInfoDO.setOrderAbstract(od.getApplyAbstract());
                executeInfoDO.setIsHasTax(od.getIsHasTax());
                executeInfoDO.setTaxRate(od.getTaxRate());
                executeInfoDO.setOrderTime(od.getOrderTime());
                executeInfoDO.setCreateTime(now);
                executeInfoDO.setUpdateTime(now);
                executeInfoDO.setUnPayApplyAmount(o.getApplyAmount());
                if(o.getId()!=null&&o.getId()>0){
                    detailRepository.findById(o.getId()).ifPresent(applyAmountOrderDetailDO -> executeInfoDO.setUnPayApplyAmount(NumberUtil.sub(o.getApplyAmount(), applyAmountOrderDetailDO.getApplyAmount())));
                }
                executeInfoDO.setId(o.getExecuteIdBySave());
                executeInfoDOS.add(executeInfoDO);
            }
        }));
        if(requestNum!=executeInfoDOS.size()){
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_DETAIL_ERROR);
        }
        return executeInfoDOS;
    }

    private TaskStartVO buildTaskStartVO(ApplyAmountOrderDO entity){
        TaskStartVO taskStartVO=new TaskStartVO();
        taskStartVO.setProcessKey(ProcessEnum.getProcessKeyByCode(entity.getTaskType()));
        taskStartVO.setMemberId(entity.getMemberId());
        taskStartVO.setRoleId(entity.getRoleId());
        taskStartVO.setDataId(entity.getId());
        return taskStartVO;
    }

    /**
     * 保存请款单
     * @author 伍将
     * @date 2021/3/11
     * @param user: 当前登录用户
     * @param saveVO: 保存请求参数
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Long> save(UserLoginCacheDTO user, ApplyAmountOrderSaveVO saveVO) {

        // 验证合同是否存在
        ContractDO contract = contractRepository.findById(saveVO.getBasics().getContractId()).orElse(null);
        if (null == contract) {
            throw new BusinessException(ResponseCode.CONTRACT_NOT_EXIST);
        }

        // 验证付款计划是否存在
        ContractPayPlanDO payPlan = payPlanRepository.findById(saveVO.getBasics().getPayPlanId()).orElse(null);
        if (null == payPlan) {
            throw new BusinessException(ResponseCode.CONTRACT_PAY_PLAN_NOT_EXIST);
        }
        // 检查付款计划是否与合同匹配
        if (!payPlan.getContractId().equals(contract.getId())) {
            throw new BusinessException(ResponseCode.CONTRACT_NOT_MATCH);
        }
        //验证付款方式
        ParamVerifyUtils.checkPayWay(saveVO.getBasics().getPayWay(),saveVO.getBasics().getPayParam());
        Double applyAmount = 0D;
        List<ContractExecuteInfoDO> executeInfoDOS=new ArrayList<>();
        if(ApplyAmountOrderSourceTypeEnum.PAY_PLAN.getCode().equals(saveVO.getBasics().getSourceType())){
            //来源：执行计划
        }else if(ApplyAmountOrderSourceTypeEnum.CONTRACT_EXECUTE.getCode().equals(saveVO.getBasics().getSourceType())){
            //来源：合同执行
            for (ApplyAmountOrderSaveDetailVO detail : saveVO.getDetailList()) {
                if(detail==null){
                    throw new BusinessException(ResponseCode.CONTRACT_EXECUTE_ID_IS_REQUIRED);
                }
                // 累计请款金额
                applyAmount += detail.getApplyAmount();
                // 如果是新增请款单，请款明细id全赋值为0
                detail.setId(saveVO.getBasics().getId() > 0 ? detail.getId() : 0);
                if(detail.getExecuteId()!=null) {
                    ContractExecuteInfoDO executeInfo = executeRepository.findById(detail.getExecuteId()).orElse(null);
                    if(executeInfo==null){
                        throw new BusinessException(ResponseCode.CONTRACT_EXECUTE_ID_IS_ERROR);
                    }
                    // 检查执行情况是否与合同匹配
                    if (!executeInfo.getContractId().equals(contract.getId())) {
                        throw new BusinessException(ResponseCode.CONTRACT_NOT_MATCH);
                    }
                }
            }
            List<ContractExecuteInfoDO> contractOrderList = getContractOrderList(user, saveVO);
            if(CollectionUtil.isNotEmpty(contractOrderList)){
                executeInfoDOS.addAll(contractOrderList);
            }
        }else{//手工
            // 检查合同执行情况是否存在
            for (ApplyAmountOrderSaveDetailVO detail : saveVO.getDetailList()) {
                if(detail==null){
                    throw new BusinessException(ResponseCode.CONTRACT_EXECUTE_ID_IS_REQUIRED);
                }
                // 累计请款金额
                applyAmount += detail.getApplyAmount();
                // 如果是新增请款单，请款明细id全赋值为0
                detail.setId(saveVO.getBasics().getId() > 0 ? detail.getId() : 0);
            }
            List<ContractExecuteInfoDO> contractOrderList = getContractOrderList(user, saveVO);
            if(CollectionUtil.isNotEmpty(contractOrderList)){
                executeInfoDOS.addAll(contractOrderList);
            }
        }
        if(CollectionUtil.isNotEmpty(executeInfoDOS)){
            //查询已有执行计划
            List<ContractExecuteInfoDO> allByContractId = contractExecuteInfoRepository.findAllByContractId(contract.getId());
            if(CollectionUtil.isNotEmpty(allByContractId)){
                Map<String, ContractExecuteInfoDO> stringContractExecuteInfoDOMap = allByContractId.stream().collect(Collectors.toMap(o -> o.getOrderNO() + ":" + o.getIsHasTax() + ":" + o.getTaxRate(), v -> v));
                executeInfoDOS.forEach(o ->{
                    ContractExecuteInfoDO executeInfoDO = stringContractExecuteInfoDOMap.get(o.getOrderNO() + ":" + o.getIsHasTax() + ":" + o.getTaxRate());
                    //如果请款订单有执行计划，则累加待请款金额
                    if(executeInfoDO!=null){
                        Double confirmApplyAmount = o.getUnPayApplyAmount();
                        BeanUtils.copyProperties(executeInfoDO,o);
                        o.setUnPayApplyAmount(NumberUtil.add(o.getUnPayApplyAmount(),confirmApplyAmount));
                        Double totalApplyAmount=NumberUtil.add(o.getUnPayApplyAmount(),o.getPayAmount());
                        if((o.getOrderAmount()>0&&totalApplyAmount.compareTo(o.getOrderAmount())>0)||(o.getOrderAmount()<0&&totalApplyAmount.compareTo(o.getOrderAmount())<0)){
                            String msg=String.format(ResponseCode.CONTRACT_APPLY_AMOUNT_GREATER_THAN_ORDER_AMOUNT.getMessage(),o.getOrderNO());
                            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_GREATER_THAN_ORDER_AMOUNT,msg);
                        }
                    }
                });
            }
        }
        // 验证请款金额
        if (!saveVO.getBasics().getApplyAmount().equals(applyAmount)) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ERROR);
        }


        // 检查请款单是否存在，基础信息id大于0时，代表更新
        ApplyAmountOrderDO oldEntity = null;
        if (saveVO.getBasics().getId() > 0) {
            oldEntity = repository.findById(saveVO.getBasics().getId()).orElse(null);
            if (null == oldEntity) {
                throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_EXIST);
            }
            // 验证是否允许修改:待提交审核、审核不通过(一级)、审核不通过(二级)状态的可以修改
            if (!ApplyAmountOrderStatusEnum.TO_BE_SUBMIT_EXAMINE.getCode().equals(oldEntity.getStatus())
                    && !ApplyAmountOrderStatusEnum.EXAMINE_NO_PASS_1.getCode().equals(oldEntity.getStatus())
                    && !ApplyAmountOrderStatusEnum.EXAMINE_NO_PASS_2.getCode().equals(oldEntity.getStatus())) {
                throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_ALLOW_UPDATE);
            }
            // 验证请款单对应合同是否保持原有一致
            if (!oldEntity.getContractId().equals(saveVO.getBasics().getContractId())) {
                throw new BusinessException(ResponseCode.CONTRACT_NOT_MATCH);
            }
        }

        Double surplus;
        // 组长请款单信息
        ApplyAmountOrderDO entity = convertApplyAmountOrderDO(saveVO.getBasics(), contract, payPlan);
        if (null != oldEntity) {
            // 如果是更新，以下旧属性不做修改
            entity.setId(oldEntity.getId());
            entity.setApplyNo(oldEntity.getApplyNo());
            entity.setTaskId(oldEntity.getTaskId());
            entity.setTaskStep(oldEntity.getTaskStep());
            entity.getTaskStepRecord().addAll(oldEntity.getTaskStepRecord());
            entity.setCreateTime(oldEntity.getCreateTime());
            surplus = NumberUtil.sub(entity.getApplyAmount(), oldEntity.getApplyAmount());
        }else{
            surplus=entity.getApplyAmount();
        }
        // 保存基础信息
        repository.saveAndFlush(entity);

        //更新合同-已请款待付款 todo ds
        double unPayApplyAmount = NumberUtil.add(contract.getUnPayApplyAmount(), surplus);
        contract.setUnPayApplyAmount(unPayApplyAmount);
        double unApplyAmount = NumberUtil.sub(contract.getUnApplyAmount(), surplus);
        contract.setUnApplyAmount(unApplyAmount);
        contractRepository.saveAndFlush(contract);
        // 启动外部流程
        Wrapper<SimpleTaskCompleteVO> taskResult = processFeignService.startSimpleProcess(buildTaskStartVO(entity));
        if (null == taskResult || ResponseCode.SUCCESS.getCode() != taskResult.getCode()
                || null == taskResult.getData()) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_WORKFLOW_ERROR);
        }
        entity.setTaskId(taskResult.getData().getTaskId());
        entity.setTaskStep(taskResult.getData().getStep());
        entity.setStatus(taskResult.getData().getStatus());
        entity.setApplyNo(CodeUtils.digits32(Constants.APPLY_AMOUNT_ORDER_PREFIX, entity.getId(), Constants.APPLY_AMOUNT_ORDER_NO_MAX_LENGTH));

        repository.saveAndFlush(entity);

        if(CollectionUtil.isNotEmpty(executeInfoDOS)){
            executeInfoDOS.forEach(o ->{
                if(o.getPayAmount()==null){o.setPayAmount(0D);}
            });
            //保存更新执行计划
            List<ContractExecuteInfoDO> executeInfoDOS1 = executeRepository.saveAll(executeInfoDOS);
            Map<String, ApplyAmountOrderSaveDetailVO> applyAmountOrderSaveDetailVOMap = saveVO.getDetailList().stream().collect(Collectors.toMap(o -> o.getOrderNO() + ":" + o.getIsHasTax() + ":" + o.getTaxRate(), o -> o));
            // 组装新增/更新数据
            List<ApplyAmountOrderDetailDO> addList = executeInfoDOS1.stream().map(o -> {
                ApplyAmountOrderDetailDO applyAmountOrderDetailDO = new ApplyAmountOrderDetailDO();
                applyAmountOrderDetailDO.setApplyId(entity.getId());
                applyAmountOrderDetailDO.setExecuteId(o.getId());
                applyAmountOrderDetailDO.setContractId(entity.getContractId());
                applyAmountOrderDetailDO.setPayPlanId(entity.getPayPlanId());
                String key=o.getOrderNO()+":"+o.getIsHasTax()+":"+o.getTaxRate();
                ApplyAmountOrderSaveDetailVO applyAmountOrderSaveDetailVO = applyAmountOrderSaveDetailVOMap.get(key);
                applyAmountOrderDetailDO.setApplyAmount(applyAmountOrderSaveDetailVO.getApplyAmount());
                Long detailId = applyAmountOrderSaveDetailVO.getId();
                applyAmountOrderDetailDO.setId((detailId==null||detailId==0)?null:detailId);
                return applyAmountOrderDetailDO;
            }).collect(Collectors.toList());
            detailService.saveList(addList);
        }
        //来源：执行计划或手工单
        // 保存请款明细
        //4.23注 detailService.save(saveVO.getDetailList(), entity.getContractId(), entity.getId(), entity.getPayPlanId());

        // 如果是新增数据，新增外部流转记录
        if (saveVO.getBasics().getId() <= 0) {
            recordService.add(user, entity.getId(), entity.getStatus(), null,ApplyAmountOrderActionEnum.ADD.getMessage(), "");
            //待提交审核请款单+1
            addNotice(entity,null,ContractApplyAmountOrderOperateTypeEnum.TO_BE_COMMIT_VALIFY);
            //发送消息
            sendContractSystemMessage(entity, MessageTemplateCode.contract_cash_wait_audit);
        }
        return Wrapper.success();
    }

    /**
     * 组装请款单
     * @author 伍将
     * @date 2021/3/11
     * @param basics: 基础信息
     * @param contract: 合同
     * @param payPlan: 付款计划
     * @return 请款单
     **/
    private ApplyAmountOrderDO convertApplyAmountOrderDO(ApplyAmountOrderSaveBasicsVO basics, ContractDO contract, ContractPayPlanDO payPlan) {
        ApplyAmountOrderDO entity = new ApplyAmountOrderDO();
        entity.setId(basics.getId() > 0 ? basics.getId() : null);
        entity.setApplyAbstract(basics.getApplyAbstract());
        entity.setStatus(ApplyAmountOrderStatusEnum.TO_BE_SUBMIT_EXAMINE.getCode());
        entity.setTaskType(ProcessEnum.CONTRACT_APPLY_AMOUNT_VERIFY.getCode());
        entity.setMemberId(contract.getPartyAMemberId());
        entity.setRoleId(contract.getPartyARoleId());
        entity.setMemberName(contract.getPartyAName());
        entity.setContractId(contract.getId());
        entity.setContractNo(contract.getContractNo());
        entity.setPayeeMemberId(contract.getPartyBMemberId());
        entity.setPayeeRoleId(contract.getPartyBRoleId());
        entity.setPayeeMemberName(contract.getPartyBName());
        entity.setPayeeName(basics.getPayeeName());
        entity.setBankAccount(basics.getBankAccount());
        entity.setBankDeposit(basics.getBankDeposit());
        entity.setPayPlanId(payPlan.getId());
        entity.setPayStage(payPlan.getPayStage());
        entity.setPayRatio(basics.getPayRatio());
        entity.setContractAmount(contract.getTotalAmount());
        entity.setApplyAmount(basics.getApplyAmount());
        entity.setPayAmount(0D);
        entity.setPayTime(0L);
        entity.setExpectPayTime(DateUtil.parse(basics.getExpectPayTime()).getTime());
        entity.setPayWay(basics.getPayWay());
        entity.setPayParam(basics.getPayParam());
        entity.setMoneyPayWay(basics.getMoneyPayWay());
        entity.setMoneyPayChannel(basics.getMoneyPayChannel());
        entity.setRemark(basics.getRemark());
        entity.setInvalidTime(System.currentTimeMillis());
        entity.setInvalidReason("");
        entity.setOrderTime(System.currentTimeMillis());
        entity.setCreateTime(System.currentTimeMillis());
        entity.setUpdateTime(System.currentTimeMillis());
        entity.setSourceType(basics.getSourceType());
        return entity;
    }

    /**
     * 删除请款单
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param deleteVO: 删除请求参数
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Void> delete(UserLoginCacheDTO user, ApplyAmountOrderDeleteVO deleteVO) {

        ApplyAmountOrderDO entity = repository.findById(deleteVO.getApplyId()).orElse(null);
        if (null == entity) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_EXIST);
        }
        if (!ApplyAmountOrderStatusEnum.TO_BE_SUBMIT_EXAMINE.getCode().equals(entity.getStatus())) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_ALLOW_DELETE);
        }

        //更新合同-已请款待付款 todo ds
        ContractDO contract = contractRepository.findById(entity.getContractId()).orElse(null);
        if (null == contract) {
            throw new BusinessException(ResponseCode.CONTRACT_NOT_EXIST);
        }
        double unPayApplyAmount = NumberUtil.sub(contract.getUnPayApplyAmount(), entity.getApplyAmount());
        contract.setUnPayApplyAmount(unPayApplyAmount);
        double unApplyAmount = NumberUtil.add(contract.getUnApplyAmount(), entity.getApplyAmount());
        contract.setUnApplyAmount(unApplyAmount);
        contractRepository.saveAndFlush(contract);

        // 删除请款单
        repository.delete(entity);

        // 删除流转记录
        recordService.delete(entity.getId());

        // 删除请款明细
        detailService.delete(entity.getId());
        //待提交审核请款单-1
        addNotice(entity,ContractApplyAmountOrderOperateTypeEnum.TO_BE_COMMIT_VALIFY,null);
        return Wrapper.success();
    }

    /**
     * 添加系统操作通知-mq
     * @param applyAmountOrderDO 请款单
     * @param increaseOperateType 要增加的操作
     * @param reduceOperateType 要减少的操作
     */
    private void addNotice(ApplyAmountOrderDO applyAmountOrderDO, ContractApplyAmountOrderOperateTypeEnum reduceOperateType, ContractApplyAmountOrderOperateTypeEnum increaseOperateType){
        OperateNoticeVO addNoticeVO = new OperateNoticeVO();
        addNoticeVO.setMemberId(applyAmountOrderDO.getMemberId());
        addNoticeVO.setRoleId(applyAmountOrderDO.getRoleId());
        addNoticeVO.setDataSource(OperateDataSourceEnum.CONTRACT_APPLY_AMOUNT_ORDER.getCode());
        if(increaseOperateType!=null) {
            addNoticeVO.setIncreaseCount(com.ssy.lingxi.contract.constant.Constants.SYS_OPERATE_NOTICE_COUNT);
            addNoticeVO.setIncreaseDataId(applyAmountOrderDO.getId());
            addNoticeVO.setIncreaseOperateType(increaseOperateType.getCode());
            addNoticeVO.setIncreaseTitle(applyAmountOrderDO.getApplyAbstract());
        }
        if(reduceOperateType!=null) {
            addNoticeVO.setReduceCount(com.ssy.lingxi.contract.constant.Constants.SYS_OPERATE_NOTICE_COUNT);
            addNoticeVO.setReduceDataId(applyAmountOrderDO.getId());
            addNoticeVO.setReduceOperateType(reduceOperateType.getCode());
        }
        feignService.addSysOperateNoticeToMQ(addNoticeVO);
    }

    /**
     * 提交审核
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param submitVO: 提交请求参数
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Void> submitExamine(UserLoginCacheDTO user, ApplyAmountOrderSubmitVO submitVO) {

        ApplyAmountOrderDO entity = repository.findById(submitVO.getApplyId()).orElse(null);
        if (null == entity) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_EXIST);
        }

        // 状态为待提交审核，才允许提交审核
        if (!ApplyAmountOrderStatusEnum.TO_BE_SUBMIT_EXAMINE.getCode().equals(entity.getStatus())) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_ALLOW_SUBMIT_EXAMINE);
        }

        // 执行工作流
        entity = processFeignService.completeSimpleTaskByApplyAmountOrder(entity, ProcessTaskStatusEnum.GOTO_NEXT_STEP.getCode());

        entity.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(entity);

        // 新增内部流转记录
        recordService.add(user, entity.getId(), entity.getStatus(), null,ApplyAmountOrderActionEnum.SUBMIT_VALIFY.getMessage(), "");
        //待提交审核请款单-1，待审核请款单（一级）+1
        addNotice(entity, ContractApplyAmountOrderOperateTypeEnum.TO_BE_COMMIT_VALIFY,ContractApplyAmountOrderOperateTypeEnum.TO_BE_VALIFY_STEP1);
        //发送消息
        sendContractSystemMessage(entity, MessageTemplateCode.contract_cash_audit_step_1);
        return Wrapper.success();
    }

    /**
     * 分页查询待审核请款单一级列表
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ApplyAmountOrderQueryVO>> pageToBeExamineOne(UserLoginCacheDTO user, ApplyAmountOrderCommonPageVO pageVO) {
        ApplyAmountOrderPageVO commonPageVO = new ApplyAmountOrderPageVO();
        BeanUtils.copyProperties(pageVO, commonPageVO);
        commonPageVO.setStatus(ApplyAmountOrderStatusEnum.TO_BE_EXAMINE_1.getCode());
        return commonPageList(user, commonPageVO, null);
    }

    /**
     * 一级审核
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param examineVO: 申请请求参数
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Void> examineStepOne(UserLoginCacheDTO user, ApplyAmountOrderExamineVO examineVO) {

        ApplyAmountOrderDO entity = checkExamineParam(examineVO);

        // 状态为待审核(一级)，才允许审核(一级)
        if (!ApplyAmountOrderStatusEnum.TO_BE_EXAMINE_1.getCode().equals(entity.getStatus())) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_ALLOW_EXAMINE);
        }

        // 执行工作流
        entity = processFeignService.completeSimpleTaskByApplyAmountOrder(entity, examineVO.getIsPass());
        entity.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(entity);

        // 新增内部流转记录
        recordService.add(user, entity.getId(), entity.getStatus(), null, ApplyAmountOrderActionEnum.EXAMINE_STEP_1.getMessage(), examineVO.getOpinion());
        //待审核请款单（一级）-1，待审核请款单（二级）+1
        addNotice(entity, ContractApplyAmountOrderOperateTypeEnum.TO_BE_VALIFY_STEP1,ContractApplyAmountOrderOperateTypeEnum.TO_BE_VALIFY_STEP2);
        //发送消息
        sendContractSystemMessage(entity, MessageTemplateCode.contract_cash_audit_step_2);
        return Wrapper.success();
    }

    /**
     * 检查审核参数
     * @author 伍将
     * @date 2021/3/10
     * @param examineVO: 审核请求参数
     * @return 合同
     **/
    private ApplyAmountOrderDO checkExamineParam(ApplyAmountOrderExamineVO examineVO) {

        // 验证审核参数
        if (!CommonBooleanEnum.NO.getCode().equals(examineVO.getIsPass()) && !CommonBooleanEnum.YES.getCode().equals(examineVO.getIsPass())) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_EXAMINE_PARAM_ERROR);
        }
        // 审核原因不能为空
        if (CommonBooleanEnum.NO.getCode().equals(examineVO.getIsPass()) && !StringUtils.hasLength(examineVO.getOpinion())) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_EXAMINE_OPINION_EMPTY);
        }

        ApplyAmountOrderDO entity = repository.findById(examineVO.getApplyId()).orElse(null);
        if (null == entity) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_EXIST);
        }

        return entity;
    }

    /**
     * 分页查询待审核请款单二级列表
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ApplyAmountOrderQueryVO>> pageToBeExamineTwo(UserLoginCacheDTO user, ApplyAmountOrderCommonPageVO pageVO) {
        ApplyAmountOrderPageVO commonPageVO = new ApplyAmountOrderPageVO();
        BeanUtils.copyProperties(pageVO, commonPageVO);
        commonPageVO.setStatus(ApplyAmountOrderStatusEnum.TO_BE_EXAMINE_2.getCode());
        return commonPageList(user, commonPageVO, null);
    }

    /**
     * 二级审核
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param examineVO: 申请请求参数
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Void> examineStepTwo(UserLoginCacheDTO user, ApplyAmountOrderExamineVO examineVO) {

        ApplyAmountOrderDO entity = checkExamineParam(examineVO);

        // 状态为待审核(二级)，才允许审核(二级)
        if (!ApplyAmountOrderStatusEnum.TO_BE_EXAMINE_2.getCode().equals(entity.getStatus())) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_ALLOW_EXAMINE);
        }

        // 执行工作流
        entity = processFeignService.completeSimpleTaskByApplyAmountOrder(entity, examineVO.getIsPass());
        entity.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(entity);

        // 新增内部流转记录
        recordService.add(user, entity.getId(), entity.getStatus(), null, ApplyAmountOrderActionEnum.EXAMINE_STEP_2.getMessage(), examineVO.getOpinion());
        //待审核请款单（二级）-1，待提交请款单+1
        addNotice(entity, ContractApplyAmountOrderOperateTypeEnum.TO_BE_VALIFY_STEP2,ContractApplyAmountOrderOperateTypeEnum.TO_BE_COMMIT);
        //发送消息
        sendContractSystemMessage(entity, MessageTemplateCode.contract_cash_submit);
        return Wrapper.success();
    }

    /**
     * 分页查询待提交请款单列表
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ApplyAmountOrderQueryVO>> pageToBeSubmit(UserLoginCacheDTO user, ApplyAmountOrderCommonPageVO pageVO) {
        ApplyAmountOrderPageVO commonPageVO = new ApplyAmountOrderPageVO();
        BeanUtils.copyProperties(pageVO, commonPageVO);
        commonPageVO.setStatus(ApplyAmountOrderStatusEnum.TO_BE_SUBMIT_PAY.getCode());
        return commonPageList(user, commonPageVO, null);
    }

    /**
     * 提交
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param submitVO: 提交请求参数
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Void> submit(UserLoginCacheDTO user, ApplyAmountOrderSubmitVO submitVO) {
        ApplyAmountOrderDO entity = repository.findById(submitVO.getApplyId()).orElse(null);
        if (null == entity) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_EXIST);
        }

        // 状态为待提交审核，才允许提交审核
        if (!ApplyAmountOrderStatusEnum.TO_BE_SUBMIT_PAY.getCode().equals(entity.getStatus())) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_ALLOW_SUBMIT);
        }

        // 执行工作流
        entity = processFeignService.completeSimpleTaskByApplyAmountOrder(entity, ProcessTaskStatusEnum.GOTO_NEXT_STEP.getCode());

        entity.setUpdateTime(System.currentTimeMillis());
        repository.saveAndFlush(entity);

        // 新增内部流转记录
        recordService.add(user, entity.getId(), entity.getStatus(), null, ApplyAmountOrderActionEnum.SUBMIT.getMessage(), "");

        // 调用结算内部接口，申请结算请款数据
        Long totalCount = detailRepository.countByApplyId(entity.getId());
        feignService.addSettlementApplyAmount(entity, totalCount);
        //待审核请款单（二级）-1，待提交请款单+1
        addNotice(entity, ContractApplyAmountOrderOperateTypeEnum.TO_BE_COMMIT,null);

        return Wrapper.success();
    }

    /**
     * 获取状态列表
     * @author 伍将
     * @date 2021/3/10
     * @return 操作结果
     **/
    @Override
    public Wrapper<List<PageItemVO>> getStatusList() {
        return Wrapper.success(Arrays.stream(ApplyAmountOrderStatusEnum.values()).map(r -> {
                    PageItemVO status = new PageItemVO();
                    status.setStatus(r.getCode());
                    status.setName(r.getMessage());
                    return status;
                }).collect(Collectors.toList())
        );
    }

    /**
     * 分页查询请款统计
     * @author 伍将
     * @date 2021/3/10
     * @param user: 当前登录用户
     * @param pageVO: 分页请求参数
     * @return 操作结果
     **/
    @Override
    public Wrapper<PageData<ApplyAmountOrderSummaryQueryVO>> pageListForSummary(UserLoginCacheDTO user, ApplyAmountOrderSummaryPageVO pageVO) {
        // step1: 远端调用结算服务查询请款付款请款
        ApplyAmountSunQueryVO queryVO = new ApplyAmountSunQueryVO();
        queryVO.setContractId(pageVO.getContractId());
        queryVO.setCurrent(pageVO.getCurrent());
        queryVO.setPageSize(pageVO.getPageSize());
        queryVO.setPartyAFlag(true);
        Wrapper<PageData<ApplyAmountSunVO>> helpPageData =  feignService.pageListForSummary(queryVO);
        if (helpPageData.getCode() != ResponseCode.SUCCESS.getCode()) {
            return Wrapper.fail(helpPageData.getCode());
        }
        // step2: 组装数据
        List<ApplyAmountOrderSummaryQueryVO> resultList = helpPageData.getData().getData().stream().map(map -> {
            ApplyAmountOrderSummaryQueryVO item = new ApplyAmountOrderSummaryQueryVO();
            item.setId(map.getId());
            item.setApplyNo(map.getApplyNo());
            item.setApplyAbstract(map.getApplyAbstract());
            item.setStatus(map.getStatus());
            item.setStatusName(map.getStatusName());
            item.setApplyTime(map.getApplyTime());
            item.setApplyAmount(map.getApplyAmount());
            item.setPayTime(map.getPayTime());
            item.setPayAmount(map.getPayAmount());
            item.setPayWayName(map.getPayWayName());
            return item;
        }).collect(Collectors.toList());
        return Wrapper.success(new PageData<>(helpPageData.getData().getTotalCount(), resultList));
    }

    /**
     * 支付请款
     * @author 伍将
     * @date 2021/3/24
     * @param payVO: 支付请求参数
     * @return 操作结果
     **/
    @Transactional
    @Override
    public Wrapper<Void> payApplyAmount(PayApplyAmountVO payVO) {
        log.info("请款单feign 付款：request:{}", JSONUtil.toJsonStr(payVO));
        ApplyAmountOrderDO entity = repository.findById(payVO.getApplyId()).orElse(null);
        if (null == entity) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_EXIST);
        }
        //已付款，直接返回
        if(ApplyAmountOrderStatusEnum.PAY.getCode().equals(entity.getStatus())){
            return Wrapper.success();
        }
        // 状态为待待付款，才允许支付
        if (!ApplyAmountOrderStatusEnum.TO_BE_PAY.getCode().equals(entity.getStatus())) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_ALLOW_PAY);
        }

        entity.setStatus(ApplyAmountOrderStatusEnum.PAY.getCode());
        long now = System.currentTimeMillis();
        entity.setUpdateTime(now);
        entity.setPayTime(now);
        entity.setPayAmount(entity.getApplyAmount());
        repository.saveAndFlush(entity);
        // 新增内部流转记录
        recordService.add(payVO.getUser(), entity.getId(), entity.getStatus(), ApplyAmountOrderStatusEnum.getMessage(entity.getStatus()), ApplyAmountOrderActionEnum.PAY.getMessage(), "");

        //更新合同金额
        ContractDO contractDO = contractRepository.findById(entity.getContractId()).orElse(null);
        if(contractDO==null){
            throw new BusinessException(ResponseCode.CONTRACT_NOT_EXIST);
        }
        double add = NumberUtil.add(contractDO.getPayAmount(), entity.getApplyAmount());
        contractDO.setPayAmount(add);
        double unpayApply = NumberUtil.sub(contractDO.getUnPayApplyAmount(), entity.getApplyAmount());
        contractDO.setUnPayApplyAmount(unpayApply);
        contractDO.setUpdateTime(now);
        contractRepository.saveAndFlush(contractDO);
        //更新合同执行支付金额
        List<ApplyAmountOrderDetailDO> applyAmountOrderDetailDOList = detailRepository.findAllByApplyId(entity.getId());
        if(CollectionUtil.isNotEmpty(applyAmountOrderDetailDOList)){
            List<Long> exeIds = applyAmountOrderDetailDOList.stream().map(ApplyAmountOrderDetailDO::getExecuteId).collect(Collectors.toList());
            if(CollectionUtil.isNotEmpty(exeIds)) {
                List<ContractExecuteInfoDO> executeInfoList = contractExecuteInfoRepository.findAllByIdIn(exeIds);
                executeInfoList.forEach(e -> applyAmountOrderDetailDOList.forEach(a ->{
                    if(e.getId().equals(a.getExecuteId())){
                        double payAmount = NumberUtil.add(e.getPayAmount(), a.getApplyAmount());
                        double unPayAmount = NumberUtil.sub(e.getUnPayApplyAmount(), a.getApplyAmount());
                        e.setPayAmount(payAmount);
                        e.setUnPayApplyAmount(unPayAmount);
                        e.setUpdateTime(now);
                    }
                }));
                contractExecuteInfoRepository.saveAll(executeInfoList);
            }
        }
        return Wrapper.success();
    }

    /**
     * 查询请款单信息
     * @param detailVO 接口参数
     * @return 查询结果
     */
    @Override
    public Wrapper<ApplyAmountOrderInfoVO> payDetailInfo(ApplyAmountOrderDetailVO detailVO) {
        ApplyAmountOrderDO entity = repository.findById(detailVO.getApplyId()).orElse(null);
        if (null == entity) {
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_EXIST);
        }else if(!entity.getContractId().equals(detailVO.getContractId())){
            throw new BusinessException(ResponseCode.CONTRACT_APPLY_AMOUNT_ORDER_NOT_EXIST);
        }
        ApplyAmountOrderInfoVO infoVO=new ApplyAmountOrderInfoVO();
        infoVO.setPayWayName(ContractPayWayEnum.getMessage(entity.getPayWay(), entity.getPayParam()));
        String moneyPayWay = OrderPayTypeEnum.getNameByCode(entity.getMoneyPayWay());
        String moneyPayChannel = OrderPayChannelEnum.getNameByCode(entity.getMoneyPayChannel());
        infoVO.setMoneyPayWayName(moneyPayWay+":"+moneyPayChannel);
        BeanUtils.copyProperties(entity,infoVO);
        //feign开票日期/编号
        InvoiceProveGetVO invoiceProveGetVO=new InvoiceProveGetVO();
        invoiceProveGetVO.setOrderNo(entity.getApplyNo());
        invoiceProveGetVO.setSettlementOrderType(SettlementOrderTypeEnum.APPLY_AMOUNT.getCode());
        List<InvoiceProveVO> invoiceProve = feignService.getInvoiceProve(invoiceProveGetVO);
        if(CollectionUtil.isNotEmpty(invoiceProve)){
            infoVO.setInvoiceProveVOList(invoiceProve);
        }
        return Wrapper.success(infoVO);
    }

    @Override
    public Wrapper<PageData<ContractOrderPageResponse>> contractOrderPageList(UserLoginCacheDTO sysUser, ContractOrderPageVO pageVO) {
        ContractOrderListRequest request=new ContractOrderListRequest();
        BeanUtils.copyProperties(pageVO,request);
        List<ContractOrderPageResponse> pageData=feignService.getContractOrderAndReturnList(sysUser,request);
        List<ContractOrderPageResponse> sortList = pageData.stream().sorted(Comparator.comparing(ContractOrderPageResponse::getOrderTime).reversed()).collect(Collectors.toList());
        //3.查询订单已请款金额
        List<ContractExecuteInfoDO> contractExecuteInfoDOS = contractExecuteInfoRepository.findAllByContractId(pageVO.getContractId());
        if(CollectionUtil.isNotEmpty(contractExecuteInfoDOS)){
            for (ContractOrderPageResponse o : sortList) {
                contractExecuteInfoDOS.forEach(p -> {
                    if (o.getOrderId().equals(p.getOrderId()) && o.getOrderType().equals(p.getOrderType()) && o.getIsHasTax().equals(p.getIsHasTax()) && o.getTaxRate().equals(p.getTaxRate())) {
                        o.setToBePayAmount(NumberUtil.sub(o.getOrderAmount().doubleValue(), NumberUtil.add(p.getPayAmount().doubleValue(), p.getUnPayApplyAmount().doubleValue())));
                    }
                });
            }
        }
        //3.合并单据信息，分页排序
        List<ContractOrderPageResponse> contractOrderPageResponses = CollectionPageUtil.pageList(sortList, pageVO.getCurrent(), pageVO.getPageSize());
        //PageData page = new PageData<>(new Integer(pageData.size()).longValue(), contractOrderPageResponses);
        return Wrapper.success(new PageData<>(new Integer(pageData.size()).longValue(), contractOrderPageResponses));
    }

    /**
     * 发送请款单模板消息-外部
     * @param applyAmountOrderDO 接口参数
     * @param messageTemplateCode 消息模板编号
     */
    private void sendContractSystemMessage(ApplyAmountOrderDO applyAmountOrderDO,String messageTemplateCode){
        SystemMessageRequest request = new SystemMessageRequest();
        request.setMemberId(applyAmountOrderDO.getMemberId());
        request.setRoleId(applyAmountOrderDO.getRoleId());
        request.setMessageNotice(messageTemplateCode);
        request.setParams(Stream.of(applyAmountOrderDO.getApplyNo(),applyAmountOrderDO.getApplyAbstract()).collect(Collectors.toList()));
        feignService.sendSystemMessage(request);
    }

    @Override
    public List<ApplyAmountOrderDO> getPaidApplyAmountOrderListByContractId(Long contractId) {
        return repository.findAllByContractIdAndStatus(contractId,ApplyAmountOrderStatusEnum.PAY.getCode());
    }
}
